/**
 * 
 */
package de.cbf.cam.dsa.model.entities.items.transfers;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;

import org.eclipse.swt.dnd.ByteArrayTransfer;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.TransferData;

import de.cbf.cam.dsa.model.entities.ArmorPart;
import de.cbf.cam.dsa.model.entities.items.Container;
import de.cbf.cam.dsa.model.entities.items.Elixir;
import de.cbf.cam.dsa.model.entities.items.Item;
import de.cbf.cam.dsa.model.entities.weapon.WeaponMelee;

/**
 * @author Nebelritter
 *
 */
@SuppressWarnings("unused")
public class ContainerTransfer extends ByteArrayTransfer implements ITransfer{
	private static final int ItemTypeItem	  		= 1<<1;
	private static final int ItemTypeContainer 		= 1<<2;
	private static final int ItemTypeElixir	 		= 1<<3;
	private static final int ItemTypeArmorPart 		= 1<<4;
	private static final int ItemTypeWeaponMelee 	= 1<<5;
	private static final int ItemTypeWeaponRanged 	= 1<<6;
	
	
	private static final String TYPENAME = "containerTransfer";

	private static final int TYPEID = registerType(TYPENAME);

	private static ContainerTransfer instance = new ContainerTransfer();
	
	public static ContainerTransfer getInstance() {
		return instance;
	}
	/* (non-Javadoc)
	 * @see org.eclipse.swt.dnd.Transfer#getTypeIds()
	 */
	@Override
	protected int[] getTypeIds() {
		return new int[] { TYPEID };
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.swt.dnd.Transfer#getTypeNames()
	 */
	@Override
	protected String[] getTypeNames() {
		return new String[] { TYPENAME };		
	}	

	boolean checkItem(Object object) {
		return (object != null && object instanceof Container);
	}

	protected boolean validate(Object object) {
		return checkItem(object);
	}
	public void javaToNative(Object object, TransferData transferData) {
	      if (!checkItem(object) || !isSupportedType(transferData)) {
	        DND.error(DND.ERROR_INVALID_DATA);
	      }
	      Container container = (Container) object;
	      try {
	    	  // write data to a byte array and then ask super to convert to
	    	  // pMedium
	    	  ByteArrayOutputStream out = new ByteArrayOutputStream();
	    	  DataOutputStream writeOut = new DataOutputStream(out);
	    	  
	    	 
	    	  writeContainer(container, writeOut);
	    	  
	        
	    	  byte[] buffer = out.toByteArray();
	    	  writeOut.close();
	    	  
	    	  super.javaToNative(buffer, transferData);
	      } catch (IOException e) {
	      }
	    }

	  public Object nativeToJava(TransferData transferData) {
	  	if (isSupportedType(transferData)) {
	  		byte[] bufferAll = (byte[]) super.nativeToJava(transferData);
	  		if (bufferAll == null){
	  			return null;
	  		}
	  		Container container = new Container("");
	  		try {
	  			ByteArrayInputStream in = new ByteArrayInputStream(bufferAll);
	  			DataInputStream readIn = new DataInputStream(in);
	  			while (readIn.available() > 20) {
	  				
	  				readContainer(container, readIn);
	  			}
	  		readIn.close();
	  		return container;
	        } catch (IOException ex) {	        	
	          return null;
	        }        
	    }
	    return null;
	  }
	  
	static void writeContainer(Container container,DataOutputStream writeOut) throws IOException{
		ItemTransfer.writeItem(container, writeOut);
		//write container specifics 		
		String volume 		= container.getVolume();
		TransferSubEntities.writeString(volume, writeOut);
		
		//write container specifics -> items
		int countOfItems 	= container.getItemsInside().size();
		writeOut.writeInt(countOfItems);		
		for(int i = 0;i<countOfItems;i++ ){
			Item item = container.getItemsInside().get(i);
			//choose correct transfer for item
			if (item instanceof Container) {
				Container containerInside = (Container) item;
				writeOut.writeInt(ItemTypeContainer);
				writeContainer(containerInside, writeOut);
				continue;
			}
			if (item instanceof Elixir) {
				Elixir elixir = (Elixir) item;
				writeOut.writeInt(ItemTypeElixir);
				ElixirTransfer.writeElixir(elixir, writeOut);
				continue;
			}
			if (item instanceof ArmorPart) {
				ArmorPart armorPart = (ArmorPart) item;
				writeOut.writeInt(ItemTypeArmorPart);
				ArmorPartTransfer.writeArmorPart(armorPart, writeOut);
				continue;
			}
			if (item instanceof WeaponMelee) {
				WeaponMelee weapon = (WeaponMelee) item;
				writeOut.writeInt(ItemTypeWeaponMelee);
				WeaponTransfer.writeWeapon(weapon, writeOut);
				continue;
			}
			//TODO (logic) weapon ranged need transfer
			//if no other item class matches
			writeOut.writeInt(ItemTypeItem);
			ItemTransfer.writeItem(item, writeOut);
		}
	}
	  
	static void readContainer(Container container,DataInputStream readIn) throws IOException{
		ItemTransfer.readItem(container, readIn);
		
		String volume   = TransferSubEntities.readString(readIn);		
		container.setVolume(volume);
		
		//read container specifics
		int countOfItems = readIn.readInt();
		for(int i = 0;i<countOfItems;i++){
			int itemType = readIn.readInt();
			switch (itemType) {
				case ItemTypeItem:{
					Item item = new Item();
					ItemTransfer.readItem(item, readIn);
					container.addItem(item);
					break;
				}
				case ItemTypeContainer:{
					Container containerInside = new Container("");
					readContainer(containerInside, readIn);
					container.addItem(containerInside);
					break;
				}
				case ItemTypeElixir:{
					Elixir elixir = new Elixir();
					ElixirTransfer.readElixir(elixir, readIn);
					container.addItem(elixir);
					break;
				}	
				case ItemTypeArmorPart:{
					ArmorPart armorPart = new ArmorPart();
					ArmorPartTransfer.readArmorPart(armorPart, readIn);
					container.addItem(armorPart);
					break;
				}	
				case ItemTypeWeaponMelee:{
					WeaponMelee armorPart = new WeaponMelee();
					WeaponTransfer.readWeapon(readIn);
					container.addItem(armorPart);
					break;
				}	
			}
		}
	}
	@Override
	public String toString() {
		return getClass().getSimpleName();
	}
}
